﻿using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using Smart.Model;
using System.Text;
using NPOI.Util;

public static class AssetBundlePacker
{
    [MenuItem("AssetBundle/SetLabels")]
    public static void SetLabels()
    {
        try
        {
            string path = $"{Application.dataPath}/Editor/Res/Table/ResourceConfig.bytes";
            var datas = System.IO.File.ReadAllBytes(path);
            var gItems = GDecoder.Load(datas,new Smart.Editor.TABLE.RESOURCECONFIGExtend());

            for (int i = 0,max = gItems.handles.Length; i < max;++i)
            {
                if(gItems.handles[i].Value is Smart.Editor.TABLE.RESOURCECONFIG config)
                {
                    var searchDir = $"{Application.dataPath}/{config.path}";
                    if(!System.IO.Directory.Exists(searchDir))
                    {
                        Smart.Model.Logger.LogError($"dir not exist for {searchDir}");
                        continue;
                    }

                    EditorUtility.DisplayProgressBar("设置AssetName名称", "正在设置AssetName名称中...", 0f);
                    DirectoryInfo dir = new DirectoryInfo(searchDir);
                    FileInfo[] files = dir.GetFiles(config.match, SearchOption.TopDirectoryOnly);
                    for (int j = 0,maxj = files.Length; j < maxj; ++j)
                    {
                        FileInfo fileInfo = files[j];
                        var pureFileName = System.IO.Path.GetFileNameWithoutExtension(fileInfo.Name);
                        EditorUtility.DisplayProgressBar("设置AssetName名称", "正在设置AssetName名称中...", 1.0f * i / files.Length);
                        string basePath = $"Assets/{config.path}/{fileInfo.Name}";
                        AssetImporter importer = AssetImporter.GetAtPath(basePath);
                        //var assetName = $"{config.bundleLabelPrefix}/{pureFileName}.u3d";
                        if (importer)
                        {
                            if (config.multi == 0)
                                importer.assetBundleName = $"{config.bundleLabelPrefix}";
                            else
                                importer.assetBundleName = $"{pureFileName}";
                        }
                        Smart.Model.Logger.Log($"<color=#3dee4f>[bundle]:[{importer.assetBundleName}]:[{fileInfo.FullName}]</color>");
                    }
                    EditorUtility.ClearProgressBar();
                }
            }
        }
        catch(System.Exception e)
        {
            EditorUtility.ClearProgressBar();
            Smart.Model.Logger.LogError($"assetbundle pack failed for {e.Message}");
        }
    }

    [MenuItem("AssetBundle/BuildBundles")]
    public static void BuildWindows()
    {
        BuildBundles(EditorUserBuildSettings.activeBuildTarget);
    }

    static void BuildBundles(BuildTarget buildTarget)
    {
        try
        {
            var bundleOutPath = $"{Application.dataPath}/../../Cache/AssetBundles/{buildTarget}/";
            if (!System.IO.Directory.Exists(bundleOutPath))
            {
                System.IO.Directory.CreateDirectory(bundleOutPath);
            }

            string path = $"{Application.dataPath}/Editor/Res/Table/ResourceConfig.bytes";
            var datas = System.IO.File.ReadAllBytes(path);
            var gItems = GDecoder.Load(datas, new Smart.Editor.TABLE.RESOURCECONFIGExtend());

            List<AssetBundleBuild> bundleMap = new List<AssetBundleBuild>(32);
            for (int i = 0, max = gItems.handles.Length; i < max; ++i)
            {
                if (gItems.handles[i].Value is Smart.Editor.TABLE.RESOURCECONFIG config)
                {
                    var searchDir = $"{Application.dataPath}/{config.path}";
                    if (!System.IO.Directory.Exists(searchDir))
                    {
                        Smart.Model.Logger.LogError($"dir not exist for {searchDir}");
                        continue;
                    }

                    DirectoryInfo dir = new DirectoryInfo(searchDir);
                    FileInfo[] files = dir.GetFiles(config.match, SearchOption.TopDirectoryOnly);
                    if (files.Length <= 0)
                        continue;

                    if(config.multi == 0)
                    {
                        AssetBundleBuild bundleItem = new AssetBundleBuild();
                        bundleItem.assetBundleName = config.bundleLabelPrefix;

                        List<string> assetNames = new List<string>(32);
                        for (int j = 0, maxj = files.Length; j < maxj; ++j)
                        {
                            FileInfo fileInfo = files[j];
                            var pureFileName = System.IO.Path.GetFileNameWithoutExtension(fileInfo.Name);
                            var assetName = $"Assets/{config.path}/{fileInfo.Name}";
                            assetNames.Add(assetName);

                            Smart.Model.Logger.Log($"<color=#3dee4f>[bundle]:[{bundleItem.assetBundleName}]:[{assetName}]</color>");
                        }
                        bundleItem.assetNames = assetNames.ToArray();

                        bundleMap.Add(bundleItem);
                    }
                    else
                    {
                        for (int j = 0, maxj = files.Length; j < maxj; ++j)
                        {
                            List<string> assetNames = new List<string>(32);
                            FileInfo fileInfo = files[j];

                            AssetBundleBuild bundleItem = new AssetBundleBuild();

                            var pureFileName = System.IO.Path.GetFileNameWithoutExtension(fileInfo.Name);
                            bundleItem.assetBundleName = $"{pureFileName}";

                            var assetName = $"Assets/{config.path}/{fileInfo.Name}";
                            assetNames.Add(assetName);

                            Smart.Model.Logger.Log($"<color=#3dee4f>[bundle]:[{bundleItem.assetBundleName}]:[{assetName}]</color>");
                            bundleItem.assetNames = assetNames.ToArray();
                            bundleMap.Add(bundleItem);
                        }
                    }
                }
            }

            // Create the array of bundle build details.
            AssetBundleBuild[] buildMap = bundleMap.ToArray();

            AssetBundleManifest manifest = BuildPipeline.BuildAssetBundles(bundleOutPath, buildMap, BuildAssetBundleOptions.None, buildTarget);

            //生成依赖文件
            StringBuilder stringBuilder = new StringBuilder(1024);

            List<ABInfo> abInfos = new List<ABInfo>(32);

            var bundles = manifest.GetAllAssetBundles();
            for(int i = 0; i < bundles.Length;++i)
            {
                var dependencies = manifest.GetAllDependencies(bundles[i]);
                stringBuilder.Clear();
                foreach(var depend in dependencies)
                {
                    if(stringBuilder.Length > 0)
                    {
                        stringBuilder.Append("|");
                    }
                    stringBuilder.Append(depend);
                }

                var bundlePath = $"{bundleOutPath}/{bundles[i]}";
                var fileMd5 = bundlePath.FileMD5();

                BuildPipeline.GetCRCForAssetBundle($"{bundleOutPath}/{bundles[i]}", out uint crc);

                ABInfo abInfo = new ABInfo();
                abInfo.bundleName = System.IO.Path.GetFileNameWithoutExtension(bundles[i]);
                abInfo.crc = crc;
                abInfo.dependencies = dependencies;
                abInfo.md5 = fileMd5;
                abInfos.Add(abInfo);

                if (stringBuilder.Length > 0)
                    Smart.Model.Logger.Log($"<color=#3dff4e>[bundle:{abInfo.bundleName}]:[hash:{fileMd5}]:[crc:{crc}] => [dependencies:{stringBuilder.ToString()}]</color>");
                else
                    Smart.Model.Logger.Log($"<color=#3dff4e>[bundle:{abInfo.bundleName}]:[hash:{fileMd5}]:[crc:{crc}] => [dependencies:No Dependencies]</color>");
            }

            var configFiles = $"{Application.dataPath}/../../Cache/Config/{buildTarget}/";
            if (!System.IO.Directory.Exists(configFiles))
            {
                System.IO.Directory.CreateDirectory(configFiles);
            }

            var configPath = $"{configFiles}/abInfo.bytes";
            if (File.Exists(configPath))
                File.Delete(configPath);

            using (FileStream fileStream = new FileStream(configPath, FileMode.Create))
            {
                fileStream.Encode(Application.version);
                Smart.Model.Logger.Log($"<color=#3dff4e>[version:{Application.version}]</color>");
                fileStream.Write(abInfos.ToArray());
                fileStream.Flush();
                fileStream.Close();
            }

            Smart.Model.Logger.Log($"<color=#3dff4e>[build abInfos succeed]</color>");
        }
        catch (System.Exception e)
        {
            EditorUtility.ClearProgressBar();
            Smart.Model.Logger.LogError($"assetbundle pack failed for {e.Message}");
        }
    }
}